/*****************************************************************************
 * Copyright (c) 2007, Ping Identity
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ping Identity, nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY PING IDENTITY ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL PING IDENTITY BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

/*!
 * @header Information Card processing context
 */
#ifndef _CONTEXT_H
#define _CONTEXT_H

#include <stdbool.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif
	
/*! 
 * @typedef ic_ctx
 * @abstract infocard context data
 * @discussion
 *	This opaque structure holds the processing information neccessary for
 *	infocard.
 *
 *	The infocard processing context is a data structure meant to hold all 
 *	configuration and state needed to process a submitted token, excluding
 *	any additional requirements that a particular token processor may need.
 *
 *	Methods using this context are assumed to be single threaded and
 *	non-reentrant; however multithreaded applications may create multiple
 *	contexts to process multiple submitted tokens at a time. A context is
 *	also meant to be re-usable across multiple requests.
 */
typedef struct ic_context_t *ic_ctx;

/*!
 * @callback ic_attribute_reporting_func
 * @abstract infocard attribute reporting callback
 * @param ctx infocard processing context
 * @param name name of attribute
 * @param format attribute format namespace, possibly NULL
 * @param value textual value of attribute
 * @param attr_context context object, if any, registered for the callback.
 *
 * @discussion
 *		This callback is implemented by a caller to receive attributes from 
 *		tokens. An implementation is registered within the context, and called
 *		during parsing for each attribute seen. The names and values are only
 *		required to be scoped for the duration of the callback, so copies must
 *		be made if any data is to be saved.
 *
 *		Note that this does not expose the underlying structure, possibly
 *		limiting access to complex data types. This limitation is done as
 *		only some tokens will be SAML, or even XML. A token processor may
 *		implement additional callbacks to expose more detailed information.
 */ 
typedef void (*ic_attribute_reporting_func) (ic_ctx ctx, 
											 const unsigned char *name, 
											 const unsigned char *format,
											 const unsigned char *value, 
											 void *attr_context);

	/*!
	 * @callback ic_replay_detection_func
	 * @abstract infocard replay detection callback
	 * @param ctx infocard processing context
	 * @param replay_value value used for replay detection. Some tokens may
	 *		require more than a single value to be used for replay detection -
	 *		this would then be an aggregate value of the replay strings
	 * @param not_on_or_after UTC expiry time for replay data sliding window. 
	 *		If set to -1, software should assume one hour from the current time.
	 *		This value is not required to match the delivered token values
	 * @param detector_context context object, if any, registered for the callback.
	 * @result true if the replay detection 
	 */
typedef bool (*ic_replay_detection_func) (ic_ctx ctx,
										  const unsigned char *replay_value,
										  time_t not_on_or_after,
										  void *detector_context);
/*!
 * @function ic_token_processing_func
 * @abstract infocard token processing callback
 * @param ctx infocard processing context
 * @param input textual/binary input data, without any transport encoding
 *		(such as HTML, URL, or Base64). This value is assumed 8-bit safe, and
 *		is not required to be nul-terminated
 * @param input_len length of input data
 */
typedef bool (*ic_token_processing_func) (ic_ctx ctx, 
										  const unsigned char *input,
										  size_t input_len);
	
/*!
 * @enum log_level
 * @abstract logging levels sent by the library through the logging function
 * @constant DEBUG_LVL - supplied for library development purposes, and are
 *		never appropriate for logging/notification. May contain user info.
 * @constant INFO_LVL - supplied for non-error reporting, such as indicating
 *		successful processing of a message. Will not contain user info.
 */
typedef enum
{
	DEBUG_LVL	= 0,
	INFO_LVL	= 1,
	// WARN_LVL	= 2,
	ERROR_LVL	= 3,
	// FATAL_LVL = 4,
} log_level;

typedef void (*ic_logger_func) (ic_ctx ctx, log_level level, const char *msg, void *logging_ctx);
	
/*!
 * @function ic_ctx_create
 * @abstract create a new (blank) infocard processing context
 * @result infocard processing context, or NULL on failure
 */
ic_ctx ic_ctx_create(void);

/*!
 * @function ic_ctx_destroy
 * @abstract release any resources associated with a processing context. After
 *		calling destroy, any ic_ctx objects are invalid and cause undefined
 *		behavior.
 * @param ctx infocard processing context
 */
void ic_ctx_destroy(ic_ctx ctx);

/*!
 * @function ic_ctx_load_certificate
 * @abstract load a pem-encoded certificate file, by relative or absolute path
 * @param ctx certificate processing context to load key into
 * @param cert_file_name relative or absolute path to the certificate file
 * @result boolean indicating success or failure. Failure reasons are reported
 *		through the logging mechanism
 */
bool ic_ctx_load_certificate(ic_ctx ctx, const char *cert_file_name);

/*!
 * @function ic_ctx_load_key
 * @abstract load a pem-encoded private key file, by relative or absolute path
 * @param ctx certificate processing context to load key into
 * @param key_file_name relative or absolute path to the private key file
 * @param password password on the key file, or NULL if none required
 * @result boolean indicating success or failure. Failure reasons are reported
 *		through the logging mechanism
 */
bool ic_ctx_load_key(ic_ctx ctx, const char *key_file_name,const char *password);

/*!
 * @funcetion ic_ctx_load_pkcs12
 * @abstract load a PKCS12 certificate and key, by relative or absolute path
 * @param ctx certificate processing context to load info into
 * @param pkcs12_file_name relative or absolute path to the PKCS12 file
 * @param password password on PKCS12 file
 * @result boolean indicating success or failure. Failure reasons are reported
 *		through the loggin mechanism
 */
bool ic_ctx_load_pkcs12(ic_ctx ctx, const char *pkcs12_file_name, const char *password);

/*!
 * @function ic_ctx_set_logger
 * @abstract set the logging mechanism to be used
 * @param logger logging function. Set to NULL to turn off logging
 * @param logger_ctx void pointer retained and used by logging mechanism. 
 *		Ignored if logger is NULL
 */
void ic_ctx_set_logger(ic_ctx ctx, ic_logger_func logger, void *logger_ctx);

/*!
 * @function ic_ctx_set_attribute_reporting
 * @abstract set the attribute reporting mechanism to be used
 * @param reporter attribute reporting function. Setting to NULL will disable
 * @param reporter_ctx pointer retained and fed into reporting mechanism.
 *		Ignored if reporter is NULL
 */
void ic_ctx_set_attribute_reporting(ic_ctx ctx,
									ic_attribute_reporting_func reporter,
									void *reporter_ctx);
	
/*!
 * @function ic_ctx_get_current_time
 * @result time since epoch
 */
time_t ic_ctx_get_current_time(ic_ctx ctx);

/*!
 * @function ic_ctx_set_current_time
 * @abstract change the time reported by ic_ctx_get_current_time, and used
 *		internally. 
 * @param current - time since epoch, or -1 for the default automatic mode
 * @discussion Setting the value to anything other than -1 will cause the
 *		specified fixed value to be used. This is primarily used for
 *		testing purposes, and is not a good idea to use from a security
 *		standpoint.
 */
void ic_ctx_set_current_time(ic_ctx ctx, time_t current);
	
void ic_ctx_set_audience(ic_ctx ctx, const unsigned char *audience);
	/*!
	 * @function ic_ctx_is_in_audience
	 * @abstract determine if the audience specified matches the local context
	 * @param audience audience string.
	 * @discussion This may be called multiple times if multiple audience 
	 *		conditions are specified.
	 */ 
	bool ic_ctx_is_in_audience(ic_ctx ctx, const unsigned char *audience);
	
	
/*!
 * @function ic_ctx_set_replay_detection
 * @abstract set the replay dection callback to be used
 * @param detector - replay detection callback to use. Setting to NULL will 
 *		cause any token processing logic requiring replay detection to fail.
 * @param detector_ctx pointer retained and fed into detection mechanism.
 *		Ignored if detector is NULL
 */
void ic_ctx_set_replay_detection(ic_ctx ctx,
							 ic_replay_detection_func detector,
							 void * detector_ctx);

/*!
 * @function ic_ctx_set_token_processor
 * @abstract set the token processor system to be used
 * @param processor - the token processor to use. By default, the processor for SAML 1.1
 * 		self-issued identities will be used.
 */
void ic_ctx_set_token_processor(ic_ctx ctx,
							ic_token_processing_func processor);

/*!
 * @function ic_set_input_doc_max_size
 * @abstract set the maximum size (in bytes) allowed for information cards
 * @discussion to help against some forms of DoS attacks, the byte count of
 *      the input document is limited by default to 8,192 bytes. Call this
 *	method to allow a larger byte count.
 */ 
void ic_ctx_set_input_doc_max_size(ic_ctx ctx, unsigned int max_size);

/*!
 * @function ic_disable_replay_detection
 * @abstract disable replay detection for testing/development environments
 * @discussion This callback implementation is provided for convenience, but
 *		is _not_ meant to be used for production deployments. In addition to
 *		allowing all replays, a informational log message will be generated
 *		to report each use.
 *
 *		The detector_context value should be set to NULL when registering with
 *		the infocard context.
 */
bool ic_disable_replay_detection(ic_ctx ctx,
									const unsigned char *replay_string,
									time_t not_on_or_after,
									void *detector_context);

/*!
 * @function ic_logger_stdout_stderr
 * @abstract log informational and error data to the standard streams
 * @discussion As a library it could be considered inappropriate to output
 * 		to stdout and stderr without the application having control
 *		over the behavior. However, outputting these messages is
 *		a common enough desired behavior that creating a built-in
 *		implementation is desirable.
 *		The logger_context value should be set to NULL when registering
 *		with the infocard context.
 */
void ic_logger_stdout_stderr(ic_ctx ctx, log_level level, const char *reason, void *logger_ctx);
/*!
 * @function ic_ctx_process_token 
 * @abstract perform processing and schema-level validation of the token
 * @discussion
 *	This function processes a token, returning a dictionary of name/value pairs.
 *	Decryption and signature validation is performed, however condition checks
 *   (not_before, not_on_or_after, audience) are not performed. The method
 *	infocard_process_token_conditions should be called after this method for
 *	that purpose.
 */
bool ic_ctx_process_token(ic_ctx ctx, const unsigned char *input, size_t input_len);

#ifdef __cplusplus
}
#endif
#endif /* _CONTEXT_H */
